package com.example.aop;

import com.example.annotation.Idempotent;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author T
 * @description 幂等性处理器 拦截@Idempotent注解的方法
 * @date 2025年05月17日 23:01
 */
@Aspect
public class IdempotentHandler {

    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.example.annotation.Idempotent)")
    public void pointHandler(){

    }


    @Around("pointHandler()")
    public Object routerHandler(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取当前请求
        ServletRequestAttributes servletRequest = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequest.getRequest();
        //获取具体的注解value属性
        String value = getIdempotentSymbol(joinPoint);
        //从请求中获取具体标识
        String tokenValue = request.getHeader(value);
        //执行业务方法前尝试从Redis中删除标识，成功则继续执行，失败则说明重复操作
        if (redisTemplate.delete(tokenValue)){
            //删除成功，继续执行
            return joinPoint.proceed();
        }else{
            throw new RuntimeException("重复操作");
        }
    }

    /**
     * @description 从注解中获取value属性值
     * @author T
     * @date 2025/5/17
     * @version 1.0
     */
    private static String getIdempotentSymbol(ProceedingJoinPoint joinPoint) {
        Idempotent annotation = joinPoint.getTarget().getClass().getAnnotation(Idempotent.class);
        return annotation.value();
    }
}
